// Object factory, uses function pointers to create objects

#pragma once

#include <map>
using std::map;

template <typename ClassIDType, typename BaseClassType>
class DHD_ObjectFactory
{
private:
	// This is the Function Pointer we declare
	typedef BaseClassType* (*ObjectCreator)(void);

	// Use a map to store and create each object
	map<ClassIDType, ObjectCreator> m_ObjectCreators;


	// Singleton instance of 
	static DHD_ObjectFactory<ClassIDType, BaseClassType> sm_Instance;

	// That trilogy we need to put in the private section
	// so this class can be a proper singleton. Be smart.
	DHD_ObjectFactory(void) {}
	DHD_ObjectFactory(const DHD_ObjectFactory&);
	DHD_ObjectFactory& operator=(const DHD_ObjectFactory&);

	~DHD_ObjectFactory(void) {}

	// Function we use to create a new object.
	template<typename DerivedClassType>
	static BaseClassType* ConstructObject(void)
	{
		return new DerivedClassType;
	}

public:

	//	GetInstance, we want that access, you know we love it.
	static DHD_ObjectFactory<ClassIDType, BaseClassType>* GetInstance(void)
	{
		return &sm_Instance;
	}

	// A map of function pointers. Pretty scary sounding
	// Really not a big dea. Get the Type of Object, First is the ID, 
	// which we use ENUMs for, just the names of our functions
	// Then just a simply call new on the object so we get a new one.
	// Ballin
	template<typename DerivedClassType>
	bool RegisterClassType(ClassIDType id)
	{
		std::pair<ClassIDType, ObjectCreator> objTypeDef;

		// Not going to explain this again.
		objTypeDef.first	=	id;
		objTypeDef.second	=	ConstructObject<DerivedClassType>;

		// Add this data into my data structure soooooo the almighty map.
		m_ObjectCreators.insert(objTypeDef);
		return true;
	}

	// Gotta remember to take info out of our almighty map
	bool UnregisterClassType(ClassIDType id)
	{
		// So we get an id, we gotta find it inside the almighty map
		map<ClassIDType, ObjectCreator>::iterator iter = m_ObjectCreators.find(id);

		// If Agents invade our program, make sure we don't let them screw everything up
		// SAVE US NEO
		if (iter == m_ObjectCreators.end())
			return false;

		// We found the correct ID, now we can get rid of it.
		m_ObjectCreators.erase(iter);
		return true;
	}
	

	BaseClassType* CreateObject(ClassIDType id)
	{

		map<ClassIDType, ObjectCreator>::iterator iter = m_ObjectCreators.find(id);

		// Neo we need you
		if( iter == m_ObjectCreators.end())
			return NULL;

		// return the created class.
		return (*iter).second();
	}

	void ShutdownObjectFactory(void)
	{
		// Get rid of everything in the map. 
		m_ObjectCreators.clear();
	}
}; // 

//	Declare static member instance at global scope
template<typename ClassIDType, typename BaseClassType>
DHD_ObjectFactory<ClassIDType, BaseClassType> 
DHD_ObjectFactory<ClassIDType, BaseClassType>::sm_Instance;


